#ifndef CIVIEW_VIEW_H
#define CIVIEW_VIEW_H

#include "../Operations/OperationManager.h"
#include "../Gui/Gui_GLOBAL.h"
#include "../Core/Orientation.h"
#include "../Core/Point2D.h"
#include "../Core/Vector2D.h"
#include "GridGround.h"
#include "Camera.h"
#include "Scene.h"
#include "FeedbackSelection.h"
#include "FeedbackTranslation.h"
#include "FeedbackScaling.h"
#include "FeedbackRotation.h"

namespace CIOps {
    class OperationManager;
    class Operation;
}

namespace CIGui {
    class ViewHeader;
}

namespace CIView {
    /**
     * This class represents the widget that will show the 3D Scene   
     **/
    class View : public QGLWidget {
        Q_OBJECT        

        //Friend classes
        friend class CIGui::ViewHeader;
        friend class CIOps::Operation;

    public:
        View (Camera::CameraType type, Scene& s, CIOps::OperationManager& om, QWidget* parent=0);    //Constructor
        virtual ~View();             

        //The possible interactive user actions
        enum {     
            NONE
          , ROTATION 
          , Z_ROTATION
          , ZOOM 
          , PAN
          , MESH_CREATION
          , SELECTION       
          , PRIMITIVES_TRANSLATION
          , PRIMITIVES_ROTATION
          , PRIMITIVES_SCALING
          , PRIMITIVES_EXTRUSION
        };  

        //The possible feedbacks mode
        enum {
            FEEDBACK_NONE
          , FEEDBACK_SELECTION
          , FEEDBACK_TRANSLATION          
          , FEEDBACK_ROTATION
          , FEEDBACK_SCALING
        };

        //The possible shade models
        enum {
            WIREFRAME
          , FLAT
          , SMOOTH
        };

        static FeedbackTranslation Feedback_Translation;    //The translation feedback
        static FeedbackScaling Feedback_Scaling;            //The scaling feedback
        static FeedbackRotation Feedback_Rotation;          //The rotation feedback
    
    public slots:     
        void SelectCamera (int index);                      //Slot method to select the current camera - [connected with cameraSelector comboBox in ViewHeader]
        void SetCameraOrientation (int x, int y, int z);    //Slot method to set the camera's orientation
        void SetVRP (float x, float y, float z);            //Slot method to set the view-reference-point position
        void SetZoomFactor (float f);                       //Slot method to set the camera zoom factor
        void SetPrimitivesSelected (bool b);                //Slot method called to set the selection status
        void ResetCurrentCamera();                          //Slot method called to reset the current camera parameters
        void ToggleLighting();                              //Slot method called to enable/disable lighting
        void SelectShadeModel (int model);                  //Slot method called to select the current shade model

    signals:
        void CurrentCameraChanged (int);
        void CameraOrientationChanged (int, int, int);
        void VrpChanged (float x, float y, float z);
        void ZoomFactorChanged (float z);
        void OperationCompleted (bool c);
        void PrimitivesSelected (bool c);
        void CurrentCameraReset (bool r);
        void LightingEnabled (bool a);
        void ShadeModelChanged();

    protected:   
        int CurrentInteractiveAction;               //The current user action
        
        static const CICore::Color DEFAULT_BACKGROUND_COLOR;
        static const CICore::Color ON_FOCUS_BACKGROUND_COLOR;

        static GridGround gridGround;               //The grid to show as ground for the scene
        std::vector<Camera*> cameras;               //The cameras of the view
        Camera* camera;                             //A pointer to the current camera through which to show the scene
        Scene& scene;                               //The 3D Scene to show
        GLenum polygonMode;                         //The polygon mode (GL_FILL, GL_LINE, etc.);

        CICore::Point2D click;                      //Mouse click coordinates
        CICore::Vector2D drag;                      //Mouse drag values
        int incrZ;                                  //The value used to rotate the camera on the z axis

        //Feedback
        unsigned int feedbackMode;                  //A booleand to indicate if selection is enabled
        FeedbackSelection feedbackSelection;        //The selection rectangle feedback

        //Operations
        CIOps::OperationManager& operationManager;  //A reference to the application operations manager
        int currentOpID;                            //An integer that identifies the current operation to do

        //Protected Utility Methods
        virtual void initializeGL();                        //Virtual method called once before the first call to paintGL() or resizeGL()
        virtual void paintGL();                             //Virtual method called whenever the widget needs to be painted
        virtual void resizeGL (int width, int height);      //Virtual method called whenever the widget has been resized

        virtual void SetModelView();                        //Virtual method called to set the model view matrix
        virtual void SetProjection();                       //Virtual method called to set the projection matrix    
        virtual void SetViewFrustum();                      //Virtual method called to set the view frustum

        void DrawAxes();                                    //Method called whenever the application needs to paint the axes
        void DrawGridGround();                              //Method called whenever the application needs to paint the grid ground
        virtual void DrawScene();                           //Virtual method called whenever the application needs to paint the scene    
        void DrawFeedback();                                //Method called whenever the application needs to paint the feedback

        void DoPanning (int x, int y);                      //Method called to do panning
        void DoZooming (int quantity);                      //Method called to do zooming

        //Keyboard events handlers
        virtual void keyPressEvent (QKeyEvent* e);          //Keyboard Pressed event handler
        virtual void keyReleaseEvent (QKeyEvent* e);        //Keyboard Released event handler    

        //Mouse events handlers
        virtual void mousePressEvent (QMouseEvent* e);      //Mouse Pressed event handler
        virtual void mouseReleaseEvent (QMouseEvent* e);    //Mouse Released event handler
        virtual void mouseMoveEvent (QMouseEvent* e);       //Mouse Moved event handler
        virtual void wheelEvent (QWheelEvent* e);           //Wheel event handler 
        virtual void focusInEvent (QFocusEvent* e);         //Focus in event handler
        virtual void focusOutEvent (QFocusEvent* e);        //Focus out event handler
        virtual void enterEvent (QEvent* e);                //Mouse Enter event handler
        virtual void leaveEvent (QEvent* e);                //Mouse Leave event handler         

    public:
        //Public Utility Methods        
        CICore::Orientation& GetCameraOrientation();        //Method called to get the current camera orientation
        int GetCameraType();                                //Method called to get the current camera type
        float GetCameraZoom();                              //Method called to get the current camera zoom value
        CICore::Point& GetCameraVrp();                      //Method called to get the current view reference point
        Scene& GetScene();                                  //Method called to get a reference to the 3D scene        

        unsigned int GetFeedbackMode();                     //Method called to get the current feedback mode
        void SetFeedbackMode (unsigned int f);              //Method called to set the current feedback mode
        FeedbackSelection& GetFeedbackSelection();          //Method called to get a reference to the selection feedback object        

        void SetInteractiveAction (int action);             //Method called to set the current interactive action
        void SetCurrentOperationID (int opID);              //Method called to set the current operation to do

        bool SelectGeometriesInVolume (double x, double y, double width, double height);    //Method called to select geometries
        bool SelectFacesInVolume (double x, double y, double width, double height);         //Method called to select faces
        bool SelectVerticesInVolume (double x, double y, double width, double height);      //Method called to select vertices
        std::pair<CIGeom::Geometry*,int> SelectVertex (double x, double y);                 //Method called to select a single vertex
    

        unsigned int SelectFeedbackTranslationAxes (double x, double y);                //Method called to select the translation feedback axes
        unsigned int SelectFeedbackScalingAxes (double x, double y);                    //Method called to select the scaling feedback axes
        unsigned int SelectFeedbackRotationAxes (double x, double y);                   //Method called to select the rotation feedback axes

        //Methods for coordinates conversion
        void WindowToWorldCoordinates (float* x, float* y);         //Method called to transform window coordinates to world coordinates
        void WindowToNormalizedCoordinates (float* x, float* y);    //Method called to transform window coordinates to normalized coordinates
    };
}

#endif // CIVIEW_VIEW_H
